#include "tool.h"
#include "midcode.h"
#include "global.h"

void print_type_value(NormalElement *ne);
void print_type(Type type);
void print_class(Class clss);
const char *print_opcode(Opcode oc);
const char *print_operand(Operand or, char *os);

void test()
{
    return;
}
//typedef struct NormalElement {
//    char name[MAX_TOKEN_LEN];
//    Class clss;
//    Type type;
//    Value value;
//    Bool initd;
//    FuncElement *scope;
//    int dcl_row;
//    int ref_num;
//    int ref_row[MAX_REF_NUM];
//} NormalElement;
void print_normal_table()
{
    int i;
    fprintf(dbgout, "##################### Normal Table #####################\n");
    fprintf(dbgout, "name\tClass\t\tType\tValue\tInitd\tScope\tDcl_row\n");
    for (i = 0; i < normal_table_p; i++) {
        fprintf(dbgout, "%s\t", normal_table[i].name);
        print_class(normal_table[i].clss);
        print_type_value(&normal_table[i]);
        fprintf(dbgout, "%s\t", (normal_table[i].initd == TRUE) ? "TRUE" : "FALSE");
        fprintf(dbgout, "%s\t", (normal_table[i].scope == NULL) ? "GLOBAL" : normal_table[i].scope->name);
        fprintf(dbgout, "%d\t", normal_table[i].dcl_row);
        fprintf(dbgout, "\n");
    }
}

//typedef struct FuncElement {
//    char name[MAX_TOKEN_LEN];
//    Class clss;
//    Type type;
//    TokenType param_list[MAX_PARAM_NUM];
//    int dcl_row;
//    int ref_num;
//    int ref_row[MAX_REF_NUM];
//} FuncElement;
void print_func_table()
{
    int i;
    fprintf(dbgout, "##################### Func Table #####################\n");
    fprintf(dbgout, "name\tClass\t\tType\tDcl_row\n");
    for (i = 0; i < func_table_p; i++) {
        fprintf(dbgout, "%s\t", func_table[i].name);
        print_class(func_table[i].clss);
        print_type(func_table[i].type);
        fprintf(dbgout, "%d\t", func_table[i].dcl_row);
        fprintf(dbgout, "\n");
    }
}

//typedef enum Class {
//    GLOBAL_VAR = 100, GLOBAL_CONST, LOCAL_VAR, LOCAL_CONST, FUNC_RET, FUNC_REG, PARAMETER,
//    // Extra Class for the convinence of set_param_for_table().
//    C_VAR, C_CONST,
//} Class;
void print_class(Class clss)
{
    char *clss_name;
    switch (clss) {
        case GLOBAL_VAR:
            clss_name = "GLOBAL_VAR";
            break;
        case GLOBAL_CONST:
            clss_name = "GLOBAL_CONST";
            break;
        case LOCAL_VAR:
            clss_name = "LOCAL_VAR";
            break;
        case LOCAL_CONST:
            clss_name = "LOCAL_CONST";
            break;
        case FUNC_RET:
            clss_name = "FUNC_RET";
            break;
        case FUNC_REG:
            clss_name = "FUNC_REG";
            break;
        case PARAMETER:
            clss_name = "PARAMETER";
            break;
        case TEMP_VAR:
            clss_name = "TEMP_VAR";
            break;
        default:
            clss_name = NULL;
            break;
    }
    fprintf(dbgout, "%s\t", clss_name);
}

//typedef enum Type {
//    T_INT = 200, T_FLOAT, T_CHAR, T_VOID,
//} Type;
//
//typedef union Value {
//    int int_val;
//    float float_val;
//    char char_val;
//} Value;
void print_type_value(NormalElement *ne)
{
    switch (ne->type) {
        case T_INT:
            fprintf(dbgout, "%s\t%d\t", "T_INT", ne->value.int_val);
            break;
        case T_FLOAT:
            fprintf(dbgout, "%s\t%d\t", "T_FLOAT", ne->value.float_val);
            break;
        case T_CHAR:
            fprintf(dbgout, "%s\t%c\t", "T_CHAR", ne->value.char_val);
            break;
        case T_VOID:
            fprintf(dbgout, "%s\t%s\t", "T_CHAR", "NULL");
            break;
        default:
            break;
    }
}

void print_type(Type type)
{
    switch (type) {
        case T_INT:
            fprintf(dbgout, "%s\t", "T_INT");
            break;
        case T_FLOAT:
            fprintf(dbgout, "%s\t", "T_FLOAT");
            break;
        case T_CHAR:
            fprintf(dbgout, "%s\t", "T_CHAR");
            break;
        case T_VOID:
            fprintf(dbgout, "%s\t", "T_VOID");
            break;
        default:
            break;
    }
}



void print_midcode_table()
{
    int i;
    char orString[STRING_LEN] = {0};
    fprintf(dbgout, "##################### Midcode Table #####################\n");
    fprintf(dbgout, "Addr\tOpcode\t\t\top1\top2\top3\n");
    for (i = 0; i < midcode_table_p; i++) {
        fprintf(dbgout, "%d\t", i);
        fprintf(dbgout, "%-16s\t", print_opcode(midcode_table[i].op0));
        fprintf(dbgout, "%s\t", print_operand(midcode_table[i].op1, orString));
        fprintf(dbgout, "%s\t", print_operand(midcode_table[i].op2, orString));
        fprintf(dbgout, "%s\t", print_operand(midcode_table[i].op3, orString));
        fprintf(dbgout, "\n");
    }
}

/*
typedef enum Opcode {
    ADD_OP, MINUS_OP, MUL_OP, DIV_OP,
    IFMT_OP, IFMET_OP, IFLT_OP, IF_LET_OP,
    IFEQ_OP, IFNE_OP,
    ASSIGN_OP, JMP_OP, PARA_OP, CALL_OP, SCANF_OP, PRINTF_OP, 
    RETV_OP, RETN_OP,
} Opcode;
*/
const char *print_opcode(Opcode oc)
{
    return OpcodeString[oc - F_OPCODE];
}

// NUM_MB, STR_MB, LVAR_MB, GLOBAL_MB, FUNC_MB, REG_MB, TMPVAR_MB, JUMP_MB,
const char *print_operand(Operand or, char *os)
{
    switch (or.operandType) {
        case NUM_MB:
            sprintf(os, "%d", or.operandCont.constOp);
            break;
        case STR_MB:
            sprintf(os, "%s", or.operandCont.stringOp);
            break;
        case FUNC_MB:
            sprintf(os, "%s", or.operandCont.funcOp->name);
            break;
        case JUMP_MB:
            sprintf(os, "%d", or.operandCont.midcOp);
            break;
        default:
            if (or.operandType == LVAR_MB || or.operandType == GLOBAL_MB || or.operandType == TMPVAR_MB) {
                sprintf(os, "%s", or.operandCont.varOp->name);
            }
            break;
    }
    return os;
}